package main

//接口
/**接口中可以定义一组方法，但不需要实现，不需要方法体，并且接口中不能包含任何变量。到某个自定义类型要使用的时候
再根据具体情况把这些方法具体实现出来
实现接口要实现所有的方法才是实现
golang中不需要显示的实现接口，因为没有implement关键字
实现接口是基于方法的，不是基于接口的
例如：
A接口 a，b方法
B接口 a,b方法
C结构体实现了ab方法，那么C实现了A接口，也可以说实现了B接口，之后要实现全部方法即可，和实际接口耦合性很低，比java松散
接口目的是为了定义规范，具体由别人来实现即可
*/

import "fmt"

// 接口的定义：定义规则，定义规范，定义某种能力
type SayHello interface {
	//这里声明没有实现的方法
	SayHello()
}

// 接口的实现：定义结构体：
type person struct {
	name string
	age  int
}

type chinese struct {
	person
}

type American struct {
	person
}

// 2.只要是自定义数据类型，就可以实现接口，不仅仅是结构体类型
type interger int

func (i interger) SayHello() {
	fmt.Println("say hi", i)
}

// 实现接口的方法
func (ch *chinese) SayHello() {
	fmt.Println("你好")
}

func (ch *American) SayHello() {
	fmt.Println("hi")
}

// 定义一个函数 专门用用来各国人打招呼的打招呼的函数，接受具备SayHello接口能力的变量
func greet(s SayHello) {
	s.SayHello()
}

func main() {
	//创建一个中国人
	c := &chinese{}
	c.age = 21
	c.name = "中国人"
	//创建一个美国人
	a := &American{
		person: person{ //内嵌结构体初始化方法
			name: "美国人",
			age:  21,
		},
	}

	//打招呼
	fmt.Print(c.name, c.age)
	greet(c)
	fmt.Print(a.name, a.age)
	greet(a)

	//1.接口本身不能创建实例，但是可以指向一个实现了该接口的自定类型变量
	//var s SayHello
	// s.SayHello()
	var s SayHello = c
	s.SayHello()

	//  2.只要是自定义数据类型，就可以实现接口，不仅仅是结构体类型
	var i interger = 10
	var s1 SayHello = i
	s1.SayHello()

}

//接口总结
//1.定义接口
//2.定义结构体
//3.让结构体实现接口方法
//4.定义函数，接受具备接口方法的变量为参数

/**
  1.接口本身不能创建实例，但是可以指向一个实现了该接口的自定类型变量
  2.只要是自定义数据类型，就可以实现接口，不仅仅是结构体类型
  3.一个自定义类型可以实现多个接口
  4.一个接口可以继承多个别的接口，这是如果要实现a接口，也必须将b接口方法也全部实现
  5.interface类型默认是一个指针(引用类型)，如果没有对interface初始化就使用，那么会输出nil
  6.空接口i没有任何方法，所以可以理解为所有类型都实现了空接口，也可以理解为我们可以把任何一个变量赋值给空接口
*/
